home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / Libraries / VideoToolbox 95.04.18 / VideoToolboxSources / WindowToEPS.c < prev    next >
Encoding:
Text File  |  1995-03-21  |  10.4 KB  |  269 lines  |  [TEXT/MMCC]

  1. /*
  2. WindowToEPS.c
  3. Copyright © 1994,1995 Denis G. Pelli
  4.  
  5.     
  6. WindowToEPS(window,filename,rectPtr,pageRectPtr,cellsPerInch,grayLevels,reflectance);
  7.  
  8.     This is a simple, but reasonably general, routine to convert a
  9. grayscale image (in window or GWorld) to a PostScript file that may be
  10. transmitted to a LaserWriter or Linotype to produce a halftone image on
  11. paper. We use it a lot, and it works well.
  12.     The filename, by convention, should end in ".eps" to indicate that
  13. it is an encapsulated postscript file, but this is not enforced. The
  14. file's type is set to 'TEXT' with creator 'EPSF'. It's a plain text
  15. file.
  16.     The PixMap must have 8 bits per pixel. The window's color table is
  17. ignored. The raw pixel value (which Apple calls an "index") is
  18. transformed by the optional reflectance array (if present), and then
  19. sent directly to the printer. If "reflectance" is NULL, then the pixel
  20. value, from 0 to 255 is interpreted by PostScript as proportional to
  21. desired reflectance, from zero to 1. If you supply a "reflectance" array
  22. the values should range from 0.0 to 1.0. The *rectPtr indicates what
  23. part of your PixMap is to be used.
  24.     The *pageRectPtr is subtle. It describes, in typographers points
  25. (1/72"), the rectangle that your image will be mapped onto on the
  26. printed page. It is essential that you keep in mind that Apple and Adobe
  27. use different coordinate systems. Both Apple and Adobe increase x from
  28. left to right. However, Apple has y increasing from top to bottom,
  29. whereas Adobe increases y from bottom to top. Adobe's origin is the
  30. lower left corner of the page, even though that point is usually not
  31. printable, since most printers can only print to within about a half
  32. inch of the edge. The pageRect, though supplied in Apple's Rect data
  33. structure, must be in Adobe's coordinates, respecting the names of the
  34. Rect structure's fields: left, top, right, bottom. So, for an image to
  35. fill most of an 8.5x11 page, with 0.5" margins, you might use the
  36. following:
  37.  
  38.         SetRect(&pageRect,0.5*72,10.5*72,8*72,0.5*72);
  39.  
  40.     In printing PostScript halftones the halftone cell size determines
  41. both the spatial and graylevel resolutions of the resulting image. For
  42. the convenience of the user this can be specified by setting either the
  43. cellsPerInch or the grayLevels argument to the desired value; the other
  44. one should be zero. If both are zero then the printer will be left at
  45. its default cell size, which is usually a good choice. Note that there
  46. need not be any particular correspondence between pixels in your image
  47. and cells in the halftone; the printer automatically resamples your
  48. image to produce the halftone.
  49.     If you set cellsPerInch to a nonzero value then the printer will be
  50. asked to print its halftone with that many halftone cells per inch. E.g.
  51. to produce a halftone original for subsequent one-to-one reproduction in
  52. a journal, you'll want the cells to be coarse enough for them to
  53. reproduce without re-screening, e.g. 100 cells per inch.
  54.     Alternatively, if you set grayLevels to a nonzero value then the
  55. printer will be asked to print its halftone with cells containing
  56. grayLevels-1 printer pixels, yielding the specified number of gray
  57. levels. E.g. you might want to force your 300 dpi LaserWriter to use big
  58. cells yielding 256 gray levels.
  59.     Here's a minimal example:
  60.  
  61.         WindowToEPS(window,"test.eps",&rect,&pageRect,0.0,0,NULL);
  62.  
  63.     To print a screen to disk, preserving the size and scale of the
  64. image, try this:
  65.  
  66.         pageRect=window->portRect;
  67.         pageRect.top*=-1;        // convert from Apple to Adobe coordinates
  68.         pageRect.bottom*=-1;    // convert from Apple to Adobe coordinates
  69.         SetRect(&paperRect,0,11*72,8.5*72,0);
  70.         CenterRectInRect(&pageRect,&paperRect);
  71.         WindowToEPS(window,"test.eps",&window->portRect,&pageRect,0,0,NULL);
  72.  
  73.     Tiling is something we often want to do, creating a huge image by
  74. taping many pages together. Simply import your EPS file into a good
  75. graphics program, e.g. PageMaker, and print with tiling.
  76.  
  77. REFERENCES
  78.  
  79. Adobe Systems (1985) PostScript Language Reference Manual, Second Edition. 
  80. Reading, MA: Addison-Wesley.
  81.  
  82. Pelli, D. G. (1987) Programming in PostScript: Imaging on paper from a mathematical
  83. description. BYTE, 12 (5), 185-202.
  84.  
  85. HISTORY:
  86. 4/21/91    dgp    wrote it
  87. 7/24/91 dgp added comment about shifting pageRect
  88. 8/24/91    dgp    Made compatible with THINK C 5.0
  89. 12/7/91    dgp    minor editing of comments
  90. 10/10/92 dgp Added support for Pixmap's that require 32-bit addressing.
  91.             Much faster now, using table-lookup instead of sprintf for 
  92.             the hex encoding.
  93.             Deleted obsolete support for THINK C 4.
  94. 4/29/93    dgp    & jas Added explanation of how to do tiling.
  95. 5/27/93    dgp    minor editing for speed and clarity
  96. 6/15/93    dgp    Fixed silly bug introduced 5/27/93 that suppressed all hex data.
  97.             Call StripAddress.
  98. 6/29/93    dgp    Changed call interface to accept a pixmap handle instead of a pointer.
  99.             The problem with accepting a pointer is that the user must remember
  100.             to lock the handle before dereferencing it to get the pointer, and
  101.             lots of people forget, leading to a mysterious crash. Now the locking
  102.             is handled internally, automatically.
  103. 6/30/93    dgp    Added example, above, showing how to print screen to disk.
  104. 7/9/93    dgp check for 32-bit addressing capability.
  105. 12/15/93 dgp added filename argument to the diagnostic messages.
  106.             Corrected grayLevels to grayLevels-1 in computing
  107.             the required number of pixels in the halftone cell.
  108. 6/18/94    dgp    can32 is now computed by calling TrapAvailable(_SwapMMUMode), which 
  109.             returns the correct answer even on Macs with dirty ROMs.
  110. 9/5/94 dgp removed assumption in printf's that int==short.
  111. */
  112. #include "VideoToolbox.h"
  113. #include <assert.h>
  114. #include <math.h>
  115. #include <Traps.h>    // _SwapMMUMode
  116. #define CREATOR 'R*ch'    /* for BBEdit */
  117.  
  118. void WindowToEPS(CWindowPtr window,char *filename,Rect *rectPtr
  119.     ,Rect *pageRectPtr,double cellsPerInch,int grayLevels,float reflectance[256])
  120. {
  121.     PixMap **pm;
  122.     FILE *file;
  123.     unsigned char *addr;
  124.     long y,bytes,width;
  125.     register long i;
  126.     unsigned short *buffer,*buffer32;
  127.     register unsigned short *word,hex[256];
  128.     register unsigned char *byte;
  129.     short pixelSize;
  130.     short rowBytes;
  131.     time_t ANSITime;
  132.     char string[100];
  133.     char mode,pmState;
  134.     static Boolean can32,is32,firstTime=1;
  135.     long gestalt;
  136.     int ok;
  137.  
  138.     assert(StackSpace()>5000);
  139.     if(firstTime){
  140.         Gestalt(gestaltAddressingModeAttr,&gestalt);
  141.         is32=gestalt&(1<<gestalt32BitAddressing);
  142.         can32=TrapAvailable(_SwapMMUMode);
  143.         firstTime=0;
  144.     }
  145.     if(IsGWorldPtr(window)){
  146.         // It's a GWorldPtr, lock the pixels.
  147.         ok=LockPixels(GetGWorldPixMap((GWorldPtr)window));
  148.         if(!ok)PrintfExit("%s: can't LockPixels on GWorld.\n",__FILE__);
  149.         pm=GetGWorldPixMap((GWorldPtr)window);
  150.     }else if(window->portVersion<0){    // Is it a CGrafPort or a GrafPort?
  151.         // It's a CGrafPort.
  152.         pm=window->portPixMap;
  153.     }else{
  154.         // It's a GrafPort.
  155.         PrintfExit("%s: source must be GWorld or color Window.\n",__FILE__);
  156.     }
  157.     if(cellsPerInch!=0.0 && grayLevels!=0.0)PrintfExit("%s(%s): "
  158.         "you may not specify BOTH cellsPerInch & grayLevels.\n"
  159.         "Set one to zero.\n",__FILE__,filename);
  160.     file=fopen(filename,"w");
  161.     if(file==NULL)PrintfExit("%s: Error in opening file “%s”.\n"
  162.         ,__FILE__,filename);
  163.     pmState=HGetState((Handle)pm);
  164.     HLock((Handle)pm);
  165.     addr=RectToAddress(*pm,rectPtr,&rowBytes,&pixelSize,NULL);
  166.     if(addr==NULL)PrintfExit("%s(%s): Bad PixMap.\n",__FILE__,filename);
  167.     if(pixelSize!=8)PrintfExit("%s(%s): "
  168.         "Sorry, pixelSize must be 8, not %d.\n",__FILE__,filename,(int)pixelSize);
  169.     time(&ANSITime);
  170.     strftime(string,sizeof(string),"%I:%M %p %A, %B %d, %Y",localtime(&ANSITime));
  171.     fprintf(file,
  172.         "%%!PS-Adobe-2.0 EPSF-1.2\n");
  173.     fprintf(file,
  174.         "%%%%Creator:%s\n",IdentifyApplication());
  175.     fprintf(file,
  176.         "%%%%For:%s\n",IdentifyOwner());
  177.     fprintf(file,
  178.         "%%%%Title:%s\n",filename);
  179.     fprintf(file,
  180.         "%%%%CreationDate:%s\n",string);
  181.     fprintf(file,
  182.         "%%%%Pages: 0\n"
  183.         "%%%%BoundingBox:%d %d %d %d\n"
  184.         ,(int)pageRectPtr->left,(int)pageRectPtr->bottom
  185.         ,(int)pageRectPtr->right,(int)pageRectPtr->top);
  186.     fprintf(file,
  187.         "%%%%EndComments\n"
  188.         "%%%%BeginProlog\n"
  189.         "%%%%EndProlog\n"
  190.         "%%%%BeginSetup\n"
  191.         "/VideoToolbox dup 25 dict def load begin\n"
  192.         "end\n"
  193.         "VideoToolbox begin\n"
  194.         "gsave\n"
  195.         "%%%%EndSetup\n");
  196.     fprintf(file,
  197.         "/nx %d def                %% pixels per raster line\n",(int)(rectPtr->right-rectPtr->left));
  198.     fprintf(file,
  199.         "/ny %d def                %% lines in image\n",(int)(rectPtr->bottom-rectPtr->top));
  200.     fprintf(file,
  201.         "/hypotenuse {dup mul exch dup mul add sqrt} bind def\n"
  202.         "/pixelsPerInch gsave initmatrix 72 0 dtransform hypotenuse grestore def\n"
  203.         "%d %d translate        %% locate lower left of image\n"
  204.         ,(int)pageRectPtr->left,(int)pageRectPtr->bottom);
  205.     fprintf(file,
  206.         "%d %d scale            %% print image with these dimensions on page\n"
  207.         ,(int)(pageRectPtr->right-pageRectPtr->left),(int)(pageRectPtr->top-pageRectPtr->bottom));
  208.     if(cellsPerInch!=0.0){
  209.         fprintf(file,
  210.             "/cellsPerInch %.2f def    %% halftone dot frequency\n",cellsPerInch);
  211.         fprintf(file,
  212.             "cellsPerInch currentscreen 4 -2 roll pop 3 1 roll setscreen\n");
  213.     }
  214.     if(grayLevels!=0){
  215.         fprintf(file,
  216.             "/cellsPerInch pixelsPerInch %.2f div def    %% halftone dot frequency\n"
  217.             ,sqrt(grayLevels-1));
  218.         fprintf(file,
  219.             "cellsPerInch currentscreen 4 -2 roll pop 3 1 roll setscreen\n");
  220.     }
  221.     fprintf(file,
  222.         "/s nx string def        %% string to hold one raster line\n"
  223.         "nx ny 8                    %% dimensions and bits/pixel of source image\n"
  224.         "[nx 0 0 ny neg 0 ny]    %% map unit square to PixMap data\n"
  225.         "{currentfile s readhexstring pop}    %% read data\n"
  226.         "bind                    %% speed up reading\n"
  227.         "image\n");
  228.     assert(sizeof(*byte)==1);    // required by our algorithm
  229.     assert(sizeof(*word)==2);    // required by our algorithm
  230.     if(reflectance==NULL)for(i=0;i<256;i++){
  231.         sprintf(string,"%02x",(int)i);
  232.         hex[i]=*(unsigned short *)string;
  233.     }else for(i=0;i<256;i++){
  234.         int j;
  235.         j=0.5+255*reflectance[i];
  236.         if(j<0)j=0;
  237.         if(j>255)j=255;
  238.         sprintf(string,"%02x",j);
  239.         hex[i]=*(unsigned short *)string;
  240.     }
  241.     width=rectPtr->right-rectPtr->left;
  242.     bytes=(width+1)*sizeof(*word);
  243.     buffer=(unsigned short *)NewPtr(bytes);
  244.     if(buffer==NULL)PrintfExit("%s(%s): "
  245.         "no room for %ld byte buffer.\n\007",__FILE__,filename,bytes);
  246.     buffer32=(unsigned short *)StripAddress(buffer);
  247.     for(y=rectPtr->top;y<rectPtr->bottom;y++){
  248.         mode=true32b;
  249.         if(can32)SwapMMUMode(&mode);
  250.         byte=addr;
  251.         word=buffer32;
  252.         for(i=0;i<width;i++) *word++ = hex[*byte++];
  253.         *word=0;
  254.         if(can32)SwapMMUMode(&mode);
  255.         fprintf(file,"%s\n",(char *)buffer);
  256.         addr+=rowBytes;
  257.     }
  258.     HSetState((Handle)pm,pmState);
  259.     DisposPtr((Ptr)buffer);
  260.     fprintf(file,
  261.         "%%%%Trailer\n"
  262.         "grestore\n"
  263.         "end\n"
  264.         "showpage\n"
  265.         "%%%%EOF\n");
  266.     fclose(file);
  267.     SetFileInfo(filename,'TEXT',CREATOR);
  268. }
  269.